home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d879.lha / DiskTest / Source / ts.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  10KB  |  398 lines

  1. /*-------------------------------------*
  2.  | File: TS.c - Text scroller routines |
  3.  +-------------------------------------------------------------*
  4.  | These routines were inspired from an example due to Martin  |
  5.  | Taillefer and published on AmigaMail; although the original |
  6.  | routines have been heavily modified, I am in debt with M.T. |
  7.  +---------------------------------------------------------+---*
  8.  | Author:  Maurizio Loreti, aka MLO or I3NOO.             |
  9.  | Address: University of Padova - Department of Physics   |
  10.  |          Via F. Marzolo, 8 - 35131 PADOVA - Italy       |
  11.  | Phone:   (39)(49) 844-313         FAX: (39)(49) 844-245 |
  12.  | E-Mail:  loreti@padova.infn.it (TCP/IP)                 |
  13.  | Home: Via G. Donizetti 6 - 35010 CADONEGHE (PD) - Italy |
  14.  *---------------------------------------------------------*/
  15.  
  16. /**
  17.  | #includes
  18. **/
  19.  
  20. #include <stddef.h>                       /* Standard library */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <exec/types.h>                   /* AmigaDOS specific */
  25. #include <clib/graphics_protos.h>
  26. #include <clib/layers_protos.h>
  27. #include <clib/gadtools_protos.h>
  28. #include <clib/intuition_protos.h>
  29. #include "main.h"                         /* Local stuff */
  30. #include "ts.h"
  31. #include "ext.h"
  32.  
  33. void AddLine(
  34.   char *s,
  35.   size_t n,
  36.   BOOL update
  37. ){
  38. /**
  39.  | Adds the string "s" ("n" bytes long) to our document:
  40.  | a new "Line" structure is added to the linked list, and
  41.  | filled; if "update" is TRUE, the text is scrolled to
  42.  | display the last line and updated.
  43. **/
  44.  
  45.   Line *pL;
  46.  
  47.   if ((pL = malloc(sizeof(Line) + n)) == NULL) {
  48.     Error("No memory for Line");
  49.   }
  50.  
  51.   pL->sl_Length = n;
  52.   strcpy(pL->sl_Text, s);
  53.   pL->sl_Forw = NULL;
  54.   if ((pL->sl_Back = lastLine) == NULL) {
  55.     firstLine = pL;
  56.   } else {
  57.     lastLine->sl_Forw = pL;
  58.   }
  59.   lastLine = pL;
  60.   numLines++;
  61.  
  62.   if (update) {
  63.     if (numLines > linesVisible) {
  64.       topLine = numLines - linesVisible;
  65.     } else {
  66.       topLine = 0;
  67.     }
  68.     UpdateScroller();
  69.   }
  70. }
  71.  
  72. void BusyState(
  73.   BOOL state
  74. ){
  75. /**
  76.  | Whenever the application is busy, this function should be called
  77.  | as BusyState(TRUE); this will change the pointer to a default
  78.  | OS 2.0 busy-pointer too, to tell the user that we are not
  79.  | listening to the IDCMP's for awhile. When finished, call
  80.  | BusyState(FALSE).
  81. **/
  82.  
  83.   static UWORD __chip waitPointer[] = {
  84.     0x0000, 0x0000, 0x0400, 0x07C0, 0x0000, 0x07C0, 0x0100, 0x0380,
  85.     0x0000, 0x07E0, 0x07C0, 0x1FF8, 0x1FF0, 0x3FEC, 0x3FF8, 0x7FDE,
  86.     0x3FF8, 0x7FBE, 0x7FFC, 0xFF7F, 0x7EFC, 0xFFFF, 0x7FFC, 0xFFFF,
  87.     0x3FF8, 0x7FFE, 0x3FF8, 0x7FFE, 0x1FF0, 0x3FFC, 0x07C0, 0x1FF8,
  88.     0x0000, 0x07E0, 0x0000, 0x0000
  89.   };
  90.  
  91.   if (state == TRUE) {
  92.     SetPointer(pWind, waitPointer, 16, 16, -6, 0);
  93.   } else {
  94.     ClearPointer(pWind);
  95.   }
  96.  
  97.   if (pWind->WLayer->Flags & LAYERREFRESH) {
  98.     RefreshView(TRUE);
  99.   }
  100. }
  101.  
  102. void ClearText(
  103.   BOOL update
  104. ){
  105. /**
  106.  | This procedure free()s all the linked list holding the
  107.  | scrolled text. If "update" is TRUE, the window scrolling
  108.  | region is really cleared.
  109. **/
  110.  
  111.   Line *pL;
  112.  
  113.   for (pL=firstLine; pL!=NULL; ) {
  114.     Line *next = pL->sl_Forw;
  115.  
  116.     free(pL);
  117.     pL = next;
  118.   }
  119.  
  120.   firstLine = lastLine = NULL;
  121.   numLines = topLine = 0;
  122.  
  123.   if (update) {
  124.     SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
  125.     RefreshView(TRUE);
  126.   }
  127. }
  128.  
  129. void InitScroller(void)
  130. {
  131. /**
  132.  | Scroller initialisation.
  133.  | - memory is obtained to hold a copy of the window raster port to
  134.  |   be used for clearing (the originel raster port is used for
  135.  |   rendering); this speeds up these operations avoiding SetAPen() etc.
  136.  | - some local global variables are initialised;
  137.  | - the scrolling region is drawn (with the help text loaded in the
  138.  |   initialisation routines).
  139. **/
  140.  
  141.   memcpy(pClearRP, (pRP = pWind->RPort), sizeof(struct RastPort));
  142.   SetDrMd(pClearRP, JAM2);
  143.   SetAPen(pClearRP, 0);
  144.   SetAPen(pRP, 1);
  145.  
  146.   fontWidth  = pWind->RPort->Font->tf_XSize;
  147.   fontHeight = pWind->RPort->Font->tf_YSize;
  148.  
  149.   bevelLeft   = pWind->BorderLeft + BEVEL_LEFT;
  150.   bevelTop    = pWind->BorderTop  + BEVEL_TOP;
  151.   bevelWidth  = BEVEL_WIDTH;
  152.   bevelHeight = BEVEL_HEIGHT;
  153.   textLeft    = bevelLeft + TEXT_XOFFSET;
  154.   textTop     = bevelTop  + TEXT_YOFFSET;
  155.  
  156.   viewWidth      = (USHORT) (bevelWidth  - 2 * (TEXT_XOFFSET) - 1);
  157.   viewHeight     = (USHORT) (bevelHeight - 2 * (TEXT_YOFFSET) - 1);
  158.   columnsVisible = viewWidth  / fontWidth;
  159.   linesVisible   = viewHeight / fontHeight;
  160.   usefulWidth    = (USHORT) (columnsVisible * fontWidth);
  161.  
  162.   RefreshView(TRUE);
  163.   SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
  164. }
  165.  
  166. void LastLine(
  167.   char *s,
  168.   size_t n
  169. ){
  170. /**
  171.  | A line is drawn at the end of the text, but NOT inserted
  172.  | in the linked list; it will then be overdrawn from the next
  173.  | AddLine()d or LastLine()d text; the text is scrolled if needed,
  174.  | to display the bottom line.
  175.  | LastLine() here is only used to display the
  176.  | "reading track X head Y" text.
  177.  | "s" is the string to be displayed, "n" bytes long.
  178. **/
  179.  
  180.   USHORT y;
  181.  
  182.   if (numLines >= linesVisible) {
  183.     topLine = numLines - linesVisible + 1;
  184.     UpdateScroller();
  185.     y = linesVisible;
  186.   } else {
  187.     y = numLines - topLine + 1;
  188.   }
  189.   y = (USHORT) (textTop + pRP->TxBaseline + fontHeight * (y - 1));
  190.   RenderLine(textLeft, y, usefulWidth, s, n);
  191. }
  192.  
  193. void RefreshView(
  194.   BOOL damage
  195. ){
  196. /**
  197.  | This function performs most of the rendering work needed.
  198.  | It looks at the current window size and adjusts its rendering
  199.  | variables in consequence; then, if the "damage" parameter is
  200.  | TRUE, this routine explicitly erases any area of the display
  201.  | in which we will not be rendering in the rendering loop: this
  202.  | erases any left over characters that could be there if the
  203.  | user sizes or rearrange the window. Finally, the routine
  204.  | determines which lines of the display need to be updated,
  205.  | and goes on to do it.
  206. **/
  207.  
  208.   USHORT i;
  209.   Line *pL;
  210.   USHORT y;
  211.  
  212. /**
  213.  | What is the top line to be rendered?
  214. **/
  215.  
  216.   if (linesVisible > numLines) {
  217.     usefulHeight = (USHORT) (numLines * fontHeight);
  218.     topLine = 0;
  219.   } else {
  220.     usefulHeight = (USHORT) (linesVisible * fontHeight);
  221.     if (topLine + linesVisible > numLines) {
  222.       topLine = numLines - linesVisible;
  223.     }
  224.   }
  225.  
  226. /**
  227.  | If the layer has been damaged (and the window is to be refreshed),
  228.  | this is handled now (the gadgetry is already OK at this moment).
  229. **/
  230.  
  231.   if (damage) {
  232.     RectFill(pClearRP,
  233.              bevelLeft - 1,
  234.              bevelTop  - 1,
  235.              bevelLeft + bevelWidth,
  236.              bevelTop  + bevelHeight);
  237.     DrawBevelBox(pRP,
  238.                  bevelLeft,     bevelTop,
  239.                  bevelWidth,    bevelHeight,
  240.                  GT_VisualInfo, pVI,
  241.                  TAG_END);
  242.   }
  243.  
  244. /**
  245.  | Do we have something to render? If yes, we find the pointer to the
  246.  | top line text, starting from the top or the bottom of the list.
  247. **/
  248.  
  249.   if (usefulHeight   &&   usefulWidth) {
  250.     int n;
  251.  
  252.     if ((n = numLines - (topLine + 1)) < topLine) {
  253.       pL = ScanList(firstLine, topLine);
  254.     } else {
  255.       pL = ScanList(lastLine, -n);
  256.     }
  257.  
  258.     y = (USHORT) (textTop + pRP->TxBaseline - fontHeight);
  259.  
  260.     if (damage   ||   (topLine >= oldTopLine + linesVisible - 1)   ||
  261.         ((oldTopLine > linesVisible) &&
  262.          (topLine <= oldTopLine - linesVisible + 1))) {
  263.       i = linesVisible;
  264.     } else if (topLine < oldTopLine) {
  265.       ScrollRaster(pRP,
  266.                    0, -((long) (oldTopLine - topLine) * fontHeight),
  267.                    textLeft,
  268.                    textTop,
  269.                    textLeft + usefulWidth - 1,
  270.                    textTop + usefulHeight - 1);
  271.  
  272.       i = oldTopLine - topLine;
  273.     } else if (topLine > oldTopLine) {
  274.       ScrollRaster(pRP,
  275.                    0, ((topLine - oldTopLine) * fontHeight),
  276.                    textLeft,
  277.                    textTop,
  278.                    textLeft + usefulWidth - 1,
  279.                    textTop + usefulHeight - 1);
  280.  
  281.       for (i = linesVisible - (topLine - oldTopLine);
  282.            pL->sl_Forw != NULL  &&  i;
  283.            i--) {
  284.         pL = pL->sl_Forw;
  285.       }
  286.  
  287.       y += (USHORT) (fontHeight * (linesVisible - (topLine - oldTopLine)));
  288.       i  = topLine - oldTopLine;
  289.     } else if (oldNumLines < numLines  &&  numLines <= linesVisible) {
  290.       for (i = oldNumLines;   pL->sl_Forw != NULL  &&  i;   i--) {
  291.         pL = pL->sl_Forw;
  292.       }
  293.  
  294.       y += (USHORT) (fontHeight * oldNumLines);
  295.       i  = numLines - oldNumLines;
  296.     } else {
  297.       i = 0;
  298.     }
  299.  
  300.     while (i--   &&   pL != NULL) {
  301.       y += fontHeight;
  302.       RenderLine(textLeft, y, usefulWidth, pL->sl_Text, pL->sl_Length);
  303.       pL = pL->sl_Forw;
  304.     }
  305.   }
  306.  
  307.   oldTopLine  = topLine;
  308.   oldNumLines = numLines;
  309. }
  310.  
  311. void SetTopLine(
  312.   UWORD n
  313. ){
  314. /**
  315.  | Sets the top line of the scroller text to "n".
  316. **/
  317.  
  318.   if (topLine != n) {
  319.     topLine = n;
  320.     RefreshView(FALSE);
  321.   }
  322. }
  323.  
  324. /*-------------------------- Local Procedures --------------------------*/
  325.  
  326. static void RenderLine(
  327.   USHORT  x,
  328.   USHORT  y,
  329.   USHORT  w,
  330.   char   *text,
  331.   size_t  len
  332. ){
  333. /**
  334.  | Render a single line of text ("text", "len" characters
  335.  | long) at the given position "x","y" (pixels). "w" is the
  336.  | length (pixels) of the rendering region.
  337. **/
  338.  
  339.   Move(pRP, x, y);
  340.   if (len > columnsVisible) {
  341.     len = columnsVisible;
  342.   }
  343.  
  344.   (void) Text(pRP, text, len);
  345.   if (len < columnsVisible) {
  346.     RectFill(pClearRP,
  347.              pRP->cp_x,
  348.              y - pRP->TxBaseline,
  349.              x + w - 1,
  350.              y - pRP->TxBaseline + fontHeight - 1);
  351.   }
  352. }
  353.  
  354. static void SetScroller(
  355.   struct Window *pW,
  356.   struct Gadget *pG,
  357.   USHORT lV,
  358.   USHORT nL,
  359.   USHORT tL
  360. ){
  361. /**
  362.  | Adjust the scroller gadget to reflect the current setting:
  363.  | "lV" lines visible, "nL" total lines and "tL" number of the
  364.  | top line.
  365. **/
  366.  
  367.   GT_SetGadgetAttrs(pG, pW, NULL,
  368.       GTSC_Visible,   lV,
  369.       GTSC_Total,     nL,
  370.       GTSC_Top,       tL,
  371.       TAG_DONE);
  372. }
  373.  
  374. static Line *ScanList(
  375.   register Line *pL,
  376.   register int n
  377. ){
  378.   register Line *pNew;
  379.  
  380.   if (n > 0) {
  381.     while (n--   &&   (pNew = pL->sl_Forw) != NULL)   pL = pNew;
  382.   } else if (n < 0) {
  383.     while (n++   &&   (pNew = pL->sl_Back) != NULL)   pL = pNew;
  384.   }
  385.   return pL;
  386. }
  387.  
  388. static void UpdateScroller(void)
  389. {
  390. /**
  391.  | Updates the text scrolling region, reflecting
  392.  | the current settings.
  393. **/
  394.  
  395.   SetScroller(pWind, pScroller, linesVisible, numLines, topLine);
  396.   RefreshView(FALSE);
  397. }
  398.